import time

from common.base.base_handler import BaseHandler
from common.third_party.save_config import save_config
from services.ad936x.model import Ad936x
from services.ad936x.schemas.configs import DoubleConfig, SingleConfig, DoubleFrequency, SingleFrequency, DoubleGain, \
    SingleGain, SingleAttenuation, DoubleAttenuation
from services.control.api import ControlApi
from settings import settings


class Ad936xHandler(BaseHandler):
    __slots__ = ['model', 'control_api']



    async def handle_direct_write_bandwidth(self, params: dict):
        index, bw = params['index'], params['bw']
        await self.model.direct_write_bandwidth(index, bw)
        return True

    async def handle_configure(self, params: dict) -> bool:
        # lte_configs = {}
        # for index in range(settings.SERVICES_MODULE_NUMBER):
        #     lte_config = self.sm_api.get_lte_config(index=index)
        #     self.sm_api.set_lte_config(index=index, config=LteConfig(amp_voltages=[0] * settings.SERVICES_MODULE_NUMBER,
        #                                                              sv_ref_voltage=lte_config.sv_ref_voltage,
        #                                                              power_calibration_value=lte_config.power_calibration_value))
        #     lte_configs[index] = lte_config

        index, config = params['index'], params['config']

        if self.model.configs[index].double > config['double']:
            raise TypeError('expected double config')

        if self.model.configs[index].double:
            config = DoubleConfig(**config)
        else:
            config = SingleConfig(**{**config, 'double': False})

        origin_config = self.model.configs[index]

        set1 = set(origin_config.dict().items())
        set2 = set(config.dict().items())
        difference = set1 - set2
        dif_dict = dict((x, y) for x, y in difference)
        dif_keys = [*dif_dict]
        to_on = []

        def intersection(lst1, lst2):
            lst3 = [value for value in lst1 if value in lst2]
            return lst3

        if len(intersection(['rx_frequency', 'rx_bandwidth', 'tx_bandwidth', 'tx_frequency'], dif_keys)) > 0:
            service_list = ['service_0_state', 'service_1_state', 'service_2_state', 'service_3_state', 'service_5v_state']

            for service in service_list:
                if await self.control_api.get_control_state(service):
                    if origin_config.rx_frequency != config.rx_frequency or origin_config.rx_bandwidth != config.rx_bandwidth or origin_config.tx_bandwidth != config.tx_frequency or (origin_config.double and origin_config.tx_frequency != config.tx_frequency):
                        await self.control_api.set_control_state(name=service, state=False)
                        to_on.append(service)

            time.sleep(5)

        self.model.configure(index, config)

        if len(intersection(['rx_frequency', 'rx_bandwidth', 'tx_bandwidth', 'tx_frequency'], dif_keys)) > 0:
            time.sleep(5)
            for service in to_on:
                await self.control_api.set_control_state(name=service, state=True)


        # for index in range(settings.SERVICES_MODULE_NUMBER):
        #     self.sm_api.set_lte_config(index=index, config=LteConfig(amp_voltages=lte_configs[index].amp_voltages,
        #                                                              sv_ref_voltage=lte_configs[index].sv_ref_voltage,
        #                                                              power_calibration_value=lte_configs[index].power_calibration_value))
        return True

    async def handle_digital_tune(self, params: dict):
        index = params['index']
        await self.model.digital_tune(index)

    async def handle_digital_tune_all(self):
        await self.model.digital_tune_all()
        return True

    async def handle_set_center_frequency(self, params: dict) -> bool:
        index, config = params['index'], params['config']

        if self.model.configs[index].double > config['double']:
            raise TypeError('expected double config')

        if self.model.configs[index].double:
            config = DoubleFrequency(**config)
        else:
            config = SingleFrequency(**{**config, 'double': False})

        self.model.configure_center_frequency(index, config)
        return True

    async def handle_set_gain(self, params: dict) -> bool:
        index, config = params['index'], params['config']

        if self.model.configs[index].double > config['double']:
            raise TypeError('expected double config')

        if self.model.configs[index].double:
            config = DoubleGain(**config)
        else:
            config = SingleGain(**{**config, 'double': False})

        self.model.configure_gain(index, config)
        return True

    async def handle_set_attenuation(self, params: dict) -> bool:
        index, config = params['index'], params['config']

        if self.model.configs[index].double > config['double']:
            raise TypeError('expected double config')

        if self.model.configs[index].double:
            config = DoubleAttenuation(**config)
        else:
            config = SingleAttenuation(**{**config, 'double': False})

        self.model.configure_attenuation(index, config)
        return True

    async def handle_get_all_configs(self) -> list[DoubleConfig | SingleConfig]:
        return self.model.configs

    async def handle_get_config(self, params: dict) -> DoubleConfig | SingleConfig:
        index = params['index']

        config: SingleConfig | DoubleConfig = self.model.configs[index]
        ch0 = self.model.get_real_uldl(index*2)
        config = config.copy(update={
            'gain_0': ch0[0],
            'attenuation_0': ch0[1]
        })
        if config.double:
            ch1 = self.model.get_real_uldl(index*2+1)
            config = config.copy(update={
                'gain_1': ch1[0],
                'attenuation_1': ch1[1]
            })

        return config

    async def handle_get_statuses(self) -> list[bool]:
        return self.model.statuses

    async def handle_get_real_uldl(self, params: dict) -> tuple[float, float]:
        index = params['index']
        return self.model.get_real_uldl(index)

    async def handle_set_night_digital_tune(self, params: dict):
        night_digital_tune = params['night_digital_tune']

        self.model.night_digital_tune = night_digital_tune
        save_config('ad/night_digital_tune', night_digital_tune)

        return True

    async def handle_get_night_digital_tune(self):
        return self.model.night_digital_tune

    async def handle_set_digital_tune_range(self, params: dict):
        index, digital_tune_range = params['index'], tuple(params['digital_tune_range'])

        self.model.digital_tune_range[index] = digital_tune_range
        save_config('ad/digital_tune_range', self.model.digital_tune_range)

        return True

    async def handle_get_digital_tune_range(self, params: dict):
        index = params['index']
        return self.model.digital_tune_range[index]

    def __init__(self) -> None:
        self.model = Ad936x()
        self.control_api = ControlApi()
        super(Ad936xHandler, self).__init__(request_queue_uuid=settings.AD936X_REQUEST_QUEUE)

        self.handle('direct_write_bandwidth', self.handle_direct_write_bandwidth)
        self.handle('configure', self.handle_configure)
        self.handle('set_center_frequency', self.handle_set_center_frequency)
        self.handle('set_gain', self.handle_set_gain)
        self.handle('set_attenuation', self.handle_set_attenuation)
        self.handle('get_all_configs', self.handle_get_all_configs)
        self.handle('get_config', self.handle_get_config)
        self.handle('get_statuses', self.handle_get_statuses)
        self.handle('digital_tune', self.handle_digital_tune)
        self.handle('digital_tune_all', self.handle_digital_tune_all)
        self.handle('get_real_uldl', self.handle_get_real_uldl)
        self.handle('set_night_digital_tune', self.handle_set_night_digital_tune)
        self.handle('get_night_digital_tune', self.handle_get_night_digital_tune)
        self.handle('set_digital_tune_range', self.handle_set_digital_tune_range)
        self.handle('get_digital_tune_range', self.handle_get_digital_tune_range)
